package com.thinkit.nosql.aspect;

import cn.hutool.core.util.ReflectUtil;
import com.thinkit.core.base.BaseContextKit;
import com.thinkit.nosql.annotation.CacheClear;
import com.thinkit.utils.utils.Checker;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class ResolvingKey {

    private static final String  targetClassName ="#clas.targetClass";

    private static final String  methodName ="#clas.method";

    private static final String  paramsName ="#p";

    private static final String  uid ="#uid";// 用户ID

    private static final String  uat ="#uat"; // 用户账户

    private static final String  uc ="#uc"; // 用户终端

    private Class<?> targetClass;

    private Method method;

    private CacheClear cacheClear;

    private Object[] args;

    ResolvingKey(Class<?> targetClass, Method method, CacheClear cacheClear){
        this.targetClass= targetClass;
        this.method= method;
        this.cacheClear= cacheClear;
    }

    public ResolvingKey args(Object[] args){
        this.args = args;
        return this;
    }

    public String resolve(){
        String[] keys = cacheClear.keys();
        if(Checker.BeNotEmpty(keys)){
             String keyStr = "";
             for(String key :keys){
                 keyStr += resolveKey(key)+"|";
             }
             return  keyStr;
        }else{
            String key = cacheClear.key();
            return resolveKey(key);
        }
    }

    private String resolveKey( String key){
        Map<String,Object> resolveParams = resolveParams(key);
        if(Checker.BeNotBlank(key)){
            key= key.replace(targetClassName,targetName()).replace(methodName,methodName()).
            replace(uid, BaseContextKit.getUserId()).replace(uat,BaseContextKit.getAccount()).
            replace(uc,BaseContextKit.getUserClient());
            if(key.contains(paramsName)){
                key=resolveParams(resolveParams,key);
            }
        }
        return filterSpecialChar(key,cacheClear.value());
    }


    private String filterSpecialChar(String key,String value){
       key= key.replaceAll("\'", "").replace("+","");
       if(Checker.BeNotBlank(value)){
           key = value+key;
       }
       return key;
    }

    private String resolveParams(Map<String,Object> paramsMap,String key){
         for(String mapKey :paramsMap.keySet()){
                Object object = paramsMap.get(mapKey);
                if(!isNotObject(object)){
                    String paramsNames = collectParamName(mapKey,key);
                    String[] paramsName=paramsNames.split("\\.");
                    String pv=getParamsVal(paramsMap.get(mapKey),paramsName);
                    if(Checker.BeBlank(pv)){
                        pv="null";
                    }
                    key = key.replace(mapKey+"."+paramsNames,pv);
                }else{
                    key = key.replace(mapKey,object.toString());
                }
         }
         return key;
    }

    private String getParamsVal(Object obj,String[] paramsName){
        for(String field:paramsName){
           Object objectVal= ReflectUtil.getFieldValue(obj,field);
           obj = objectVal;
        }
        if(obj!=null){
            return obj.toString();
        }
        return null;
    }

    private  void buildParams(Map<String,Object> paramsMap,String key, int index){
        int i = key.indexOf(paramsName,index)+1;
        if(i!=0){
            int start = i+1;
            boolean f= true;
            while (f){
                i++;
                f= i< key.length() && StringUtils.isNumeric(String.valueOf(key.charAt(i)));
            }
            Integer pindex = Integer.valueOf(key.substring(start,i));
            paramsMap.put(paramsName+pindex,args[pindex]);
            //System.out.println(key.substring(start,i));
            buildParams(paramsMap,key,start-1);
        }
    }


    private Map<String,Object> resolveParams(String key){
        Map<String,Object> paramsMap=new HashMap<>();
        buildParams(paramsMap,key,0);
        return paramsMap;
    }

    private String targetName(){
        Class<?> targetClz = targetClass;
        Class<?>[] clas = cacheClear.clas();
        if(clas.length!=0){
            targetClz = clas[0];
        }
        return targetClz.toString();
    }

    private String methodName(){
        String methodName= cacheClear.method();
        if(Checker.BeBlank(methodName)){
            methodName = method.getName();
        }
        return methodName;
    }


    private  String collectParamName(String p,String key){
        int index = key.indexOf(p)+p.length();
        //System.out.println(key.charAt(index));
        boolean f = true;
        String fr = "";
        while (f){
            index++;
            if(index<key.length() &&  !"+".equals(String.valueOf(key.charAt(index)))){
                fr+=String.valueOf(key.charAt(index));
            }else{
                f =false;
            }
        }
        return fr;
    }

    public boolean isNotObject(Object o){
        boolean isPrimitive = o.getClass().isPrimitive();
        boolean isNotObj= o instanceof String ||  o instanceof Number|| o instanceof Boolean|| o instanceof Character;
        return isPrimitive || isNotObj;
    }


    public static void main(String[] args) {
        String key = "#d#p30+'.'+#p1 #p3#p0.dto.u";
        int index = key.indexOf("#p0");//key.sutring();
        String[] arrs= new String[]{};
        // bui("#p0",key,args);
//        System.out.println();
//        int i = key.indexOf(paramsName)+1;
//        int start = i+1;
//        System.out.println(i);
//        boolean f= true;
//        while (f){
//            i++;
//            f=StringUtils.isNumeric(String.valueOf(key.charAt(i)));
//        }
//        System.out.println(i);
//        System.out.println(key.substring(start,i));
       // Map<String,Object> paramsMap=new HashMap<>();
       // buildParams(paramsMap,key,0);
     //   System.out.println(paramsMap);

        // 基本类型判断
        System.out.println( Integer.class.isPrimitive());
        System.out.println(int.class.isPrimitive());
        System.out.println(void.class.isPrimitive());
        System.out.println( ResolvingKey.class.isPrimitive());
        System.out.println(Class.class.isPrimitive());
    }
}
